DynamicQuant ================= 将 FP32 输入张量按给定的 scale 和 zero point(zp)动态量化为 INT8 输出张量。 支持按整张量量化或按指定轴分段量化(per-axis dynamic quantization)。 .. math:: q_i = \mathrm{clip}\left( \mathrm{round}\left( \frac{x_i}{scale} + zp \right), q_{min}, q_{max} \right) 其中: - :math:`x_i` 为输入浮点值 - :math:`scale` 为量化比例因子 - :math:`zp` 为零点(zero point) - :math:`q_{min} = -128` - :math:`q_{max} = 127` 当输入为 :math:`+\infty` 或 :math:`-\infty` 时,输出分别饱和到最大或最小量化值。 --- 输入: - **real_values** - 输入 FP32 数据地址 - **element_num** - 输入元素总数 - **scale** - 量化 scale 数组地址 - **zp** - 量化 zero point 数组地址 - **segment_num** - 分段数量(用于按轴量化) - **axis_num** - 量化轴标识 - ``0``:整张量量化(per-tensor) - ``!=0``:按轴分段量化(per-axis) 输出: - **quant_values** - 输出 INT8 量化结果地址 --- 支持平台: ``FT78NE`` ``MT7004`` --- .. note:: - 当前算子仅支持 **FP32\Fp16 → INT8** 的动态量化 - 当 ``axis_num = 0`` 时,仅使用 ``scale[0]`` 与 ``zp[0]`` 进行整张量量化 - 当 ``axis_num != 0`` 时,输入按 ``segment_num`` 进行分段,每段使用对应的 ``scale[i]`` 与 ``zp[i]`` - 分段大小通过 ``UP_DIV(element_num, segment_num)`` 计算,最后一段自动处理剩余元素 - 量化结果会被限制在 ``[-128, 127]`` 范围内 --- **私有存储版本:** .. c:function:: void fp_QuantData_p(float* real_values, int8_t* quant_values, int element_num, float* scale, int* zp, int segment_num, int axis_num) .. c:function:: void hp_QuantData_p(half* real_values, half* quant_values, int element_num, half* scale, int* zp, int segment_num, int axis_num) --- **C调用示例:** .. code-block:: c :linenos: :emphasize-lines: 11 #include #include int main(int argc, char* argv[]) { float *input = (float *)0x10000000; // FP32 输入 int8_t *output = (int8_t *)0x10004000; // INT8 输出 float scale[4] = {0.1f, 0.12f, 0.11f, 0.09f}; int zp[4] = {0, 0, 0, 0}; int element_num = 1024; int segment_num = 4; int axis_num = 1; fp_QuantData_p(input, output, element_num, scale, zp, segment_num, axis_num); return 0; } --- **共享存储版本:** .. c:function:: void fp_QuantData_s(float* real_values, int8_t* quant_values, int element_num, float* scale, int* zp, int segment_num, int axis_num, int core_mask) .. c:function:: void hp_QuantData_s(half* real_values, half* quant_values, int element_num, half* scale, int* zp, int segment_num, int axis_num, int core_mask) --- **C调用示例:** .. code-block:: c :linenos: :emphasize-lines: 11 #include #include int main(int argc, char* argv[]) { float *input = (float *)0x10000000; // FP32 输入 int8_t *output = (int8_t *)0x10004000; // INT8 输出 float scale[4] = {0.1f, 0.12f, 0.11f, 0.09f}; int zp[4] = {0, 0, 0, 0}; int element_num = 1024; int segment_num = 4; int axis_num = 1, core_mask = 0xff; fp_QuantData_s(input, output, element_num, scale, zp, segment_num, axis_num, core_mask); return 0; } --- **实现说明:** - 当 ``axis_num == 0`` 时: - 对整个输入数组执行一次统一量化 - 等价于 per-tensor quantization - 当 ``axis_num != 0`` 时: - 输入数据按 ``segment_num`` 均分为多个分段 - 每个分段使用独立的 ``scale[i]`` 与 ``zp[i]`` - 等价于 per-axis dynamic quantization - 核心量化过程由 ``DoQuantizeFp32ToInt8`` 完成,包括: - 反 scale 计算 - 四舍五入 - 饱和裁剪 - INF 特殊值处理